一:事务概述

个人认为:一件事情由n个组成单元(步骤)组成,这些步骤同时成功或失败,他们组成了一个事务。

1.MySQL的事务(了解)

MySQL默认的事务:执行一条SQL语句,就默认的开启了事务并且提交了事务。

手动事务:

都有多条SQL语句执行时,且他们之间是相关的,必须同时成功或失败的,就需要手动开启关闭事务。

(1)显示的开启一个事务:start transaction

(2)事务的提交:commit代表从开启事务到事务提交 中间的(start到commit之间)所有的sql都认为有效 真正的更新数据库

(3)事务的回滚: rollback 代表事务的回滚 从开启事务到事务回滚 中间的所有的 sql操作都认为无效。

2.JDBC事务的操作

执行sql语句:executeUpdate() —- 每执行一次executeUpdate方法 代表 事务自动提交。

它其中的API包括:

开启事务:conn.setAutoCommit(false); —是否自动提交。

提交事务:conn.commit();

回滚事务:conn.rollback();

二:DBUtils事务的操作(重点:多条sql语句的执行)

1.QueryRunner有参数的构造: QueryRunner runner = new QueryRunner(DBUtils dataSource);

有参构造拿到一个数据源(连接池)作为参数传入QueryRunner,QueryRunner会从数据源中获得一个数据库的连接器,但是每次拿取绝大多数并不是同一个Connection,所以使用无参构造。

2.QueryRunner无参数的构造:QueryRunner runner = new QueryRunner(); 直接使用DBUtils里面的方法获得连接器。

DBUtils.getCurrentConnection(); 以示区分我写成getCurrentConnection()即获得同一个Connection。
3.DBUtils处理事务的方法:

开启事务:DBUtils.startTransaction();

事务的提交:DBUtils.commitAndRelease();

事务的回滚:DBUtils.rollback();

三:使用ThreadLocal绑定连接资源

有一个问题,我们的dao层与service层都需要使用到Connection对象,且如果service层向dao层传入Connection的话,Connection对象不一致(从连接池中getConnection每次拿取不同),即使事务成功的提交,仍然不能够实现功能。这里就需要用到ThreadLocal。

ThreadLocal:当前线程里的一个存储集合,里面底层是一个map,有着key与value。

我们的目的是:将conn资源绑定到ThreadLocal上,这样一来一个事务就拥有相同的Connection。
每条线程都对应一个Thread,这样一来就可以存储Connection,key默认为该线程,value则为连接器Connection.
注意:Connection conn = DBUtils.getCurrentConnection();在dao层中进行。

四:DBUtils工具类内部解析

我们重写我们的DBUtils,让它拥有处理事务的能力,包括开启,提交,回滚事务的方法。

且原本的或者连接池,获取Connection连接器方法仍然不变,只是现在的获取连接器的方法需要从ThreadLocal里面拿取Connection。下图为DBUtils类内部:

五:案例—实现银行转账的模型

1.技术分析
(1)在数据库中拥有多个人的信息,里面包括他们的钱money,通过jsp页面的表单操作,实现他们的相互转款的名称,金额输入。

(2)表单的数据被web层接收,并传入到service层进行事务处理,同时dao层里面设置扣钱和存钱的两个方法供service层调用。

(3)service层再进行结果判断,转账成功与否返回到web层,进行页面的显示。

2.代码的实现

构造的简单jsp表单,通过EL表达式传给对应根路径下的servlet


3.web层
获取到表单数据传入到service层,最后service层返回结果 isTransferSuccess。

4.service层
service层收到web传来的表单数据,进行事务处理。调用dao层方法,finally处提交事务。失败的话,事务回滚,SQL语句不会执行,相当于只是开启和提交关闭事务。

5.dao层
注意:从DBUtils里面获取该线程的Connection,再进行操作。

六:事务的特征和隔离级别(了解背诵概念—面试题)

1.事务的特性ACID
(1)原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作 要么都发生,要么都不发生。
(2)一致性(Consistency)一个事务中,事务前后数据的完整性必须保持一致。
(3)隔离性(Isolation)多个事务,事务的隔离性是指多个用户并发访问数据库时, 一个用户的 事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
(4)持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变 就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

2.并发访问问题—-由隔离性引起
如果不考虑隔离性,事务存在3中并发访问问题。

1)脏读:B事务读取到了A事务尚未提交的数据 —— 要求B事务要读取A事 务提交的数据

2)不可重复读:一个事务中 两次读取的数据的内容不一致 —– 要求的是一个事 务中多次读取时数据是一致的 — unpdate

3)幻读/虚读:一个事务中 两次读取的数据的数量不一致 —– 要求在一个事务多 次读取的数据的数量是一致的 –insert delete

3.事务的隔离级别
1)read uncommitted : 读取尚未提交的数据 :哪个问题都不能解决

2)read committed:读取已经提交的数据 :可以解决脏读 —- oracle默认的

3)repeatable read:重读读取:可以解决脏读 和 不可重复读 —mysql默认的

4)serializable:串行化:可以解决 脏读 不可重复读 和 虚读—相当于锁表

注意:mysql数据库默认的隔离级别

查看mysql数据库默认的隔离级别:select @@tx_isolation

设置mysql的隔离级别:set session transaction isolation level 设置事务隔离级别